﻿@page "/attributetile"
@using Gurux.DLMS.AMI.Client.Helpers
@using Gurux.DLMS.AMI.Shared.DIs
@using Gurux.DLMS.AMI.Shared.DTOs
@using Gurux.DLMS.Enums
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using System.Globalization

<CascadingValue Value="this">
    <div style="width:100%">
        @if (!string.IsNullOrEmpty(Text))
        {
            <div class="form-group">
                @if (@Index == 0)
                {
                    <label>@Name</label>
                }
                else
                {
                    <input type="checkbox" checked="@IsSelected()" @onchange="@((ChangeEventArgs __e) => ToggleRow(Convert.ToBoolean(__e.Value)))" />
                    <label>@Index @Name</label>
                }
                &emsp;
                @if (Attribute?.Template?.Unit is string unit)
                {
                    <label>@unit</label>
                }
                &emsp;
                @if (Attribute != null && Attribute.Modified)
                {
                    <span class="oi oi-warning" style="color: cornflowerblue;" aria-hidden="true" />
                }
                @if (Values != null && Values.Any())
                {
                    <select class="form-select" @bind="InternalText" disabled="@IsDisabled()">
                        @foreach (string it in Values)
                        {
                            <option value="@it">@it</option>
                        }
                    </select>
                }
                else
                {
                    <input type="text" class="form-control" disabled="@IsDisabled()" @bind="InternalText" />
                }
            </div>
        }
        else if (@Attribute != null && @Attribute.Template != null)
        {
            @if (@Attribute.Template.DataType == (int)Gurux.DLMS.Enums.DataType.Boolean)
            {
                <div class="form-group">
                    <input type="checkbox" checked="@IsSelected()" @onchange="@((ChangeEventArgs __e) => ToggleRow(Convert.ToBoolean(__e.Value)))" />
                    <Switch Text="@(Attribute.Template.Index + " " + Attribute.Template.Name)"
                            Value="@IsChecked()" Disabled="@IsDisabled()">
                        @if (Attribute != null && Attribute.Modified)
                        {
                            <span class="oi oi-warning" style="color: cornflowerblue;" aria-hidden="true" blue-color />
                        }
                        &emsp;<a href="@GetPath()" class="oi oi-folder" style="color: cornflowerblue;" />
                    </Switch>
                </div>
            }
            else @if (@Attribute.Template.ListItems != null && @Attribute.Template.ListItems.Any())
            {
                <div class="form-group">
                    <Tooltip Title="@LastRead">
                        <label>@GetName()</label>
                        &emsp;<a href="@GetPath()" class="oi oi-folder" style="color: cornflowerblue;" />
                    </Tooltip>
                    <select class="form-select" value="@GetAttributeValue(@Attribute)"
                            @onchange="@((ChangeEventArgs __e) => UpdateValue(@Attribute, __e.Value))"
                            disabled="@IsDisabled()">
                        @foreach (var li in Attribute.Template.ListItems)
                        {
                            <option value="@li.Value">@li.UIValue</option>
                        }
                    </select>
                    &emsp;
                    @if (Attribute?.Template?.Unit is string unit)
                    {
                        <label>@unit</label>
                    }
                    &emsp;
                    @if (Attribute != null && Attribute.Modified)
                    {
                        <span class="oi oi-warning" style="color: cornflowerblue;" aria-hidden="true" />
                    }
                </div>
            }
            else @if (Values != null && Values.Any())
            {
                <div class="form-group">
                    <Tooltip Title="@LastRead"><label>@GetName()</label></Tooltip>
                    &emsp;<a href="@GetPath()" class="oi oi-folder" style="color: cornflowerblue;" />
                    <select class="form-select" value="@GetAttributeValue(@Attribute)"
                            @onchange="@((ChangeEventArgs __e) => UpdateValue(@Attribute, __e.Value))"
                            disabled="@IsDisabled()">
                        @foreach (var li in Values)
                        {
                            <option value="@li">@li</option>
                        }
                    </select>
                    &emsp;
                    @if (Attribute?.Template?.Unit is string unit)
                    {
                        <label>@unit</label>
                    }
                    &emsp;
                    @if (Attribute != null && Attribute.Modified)
                    {
                        <span class="oi oi-warning" style="color: cornflowerblue;" aria-hidden="true" />
                    }
                </div>
            }
            else
            {
                <div class="form-group">
                    <div style="display: inline;">
                        <Tooltip Title="@LastRead">
                            <input type="checkbox" checked="@IsSelected()" @onchange="@((ChangeEventArgs __e) => ToggleRow(Convert.ToBoolean(__e.Value)))" />
                            <label>@GetName()</label>
                            &emsp;
                            @if (Attribute?.Template?.Unit is string unit)
                            {
                                <label>@unit</label>
                            }
                            @if (Attribute != null && Attribute.Modified)
                            {
                                <span class="oi oi-warning" style="color: cornflowerblue;" aria-hidden="true" />
                            }
                            &emsp;
                            <a href="@GetPath()" class="oi oi-folder" style="color: cornflowerblue;" />
                        </Tooltip>
                    </div>
                    @if (!HideValue)
                    {
                        <input type="text" class="form-control" disabled="@IsDisabled()" value="@GetAttributeValue(@Attribute)"
                               @onchange="@((ChangeEventArgs __e) => UpdateValue(@Attribute, __e.Value))" />
                    }
                </div>
            }
        }
    </div>
    @ChildContent
</CascadingValue>

@code {

    [CascadingParameter]
    private ObjectView? Parent { get; set; }

    private string GetPath()
    {
        return "/history/" + Attribute?.Id;
    }

    GXAttribute? _attribute;

    private string LastRead
    {
        get
        {
            return "Last read: " + Attribute?.Read;
        }
    }

    private string GetName()
    {
        if (!string.IsNullOrEmpty(Name) || Attribute?.Template == null)
        {
            return Name;
        }
        return Attribute.Template.Index + " " + Attribute.Template.Name;
    }

    /// <summary>
    /// Is attribute selected.
    /// </summary>
    /// <param name="selected">Selected item.</param>
    /// <returns>True, if the row is selected.</returns>
    protected string? IsSelected()
    {
        bool ret = false;
        if (Attribute != null && Parent != null)
        {
            ret = Parent.IsSelected(Attribute);
        }
        if (ret)
        {
            return "checked";
        }
        return null;
    }


    /// <summary>
    /// Select or de-select the attribute.
    /// </summary>
    /// <param name="selected">Selected item</param>
    protected void ToggleRow(bool select)
    {
        if (Attribute != null && Parent != null)
        {
            Parent.ToggleAttribute(Attribute);
        }
    }

    protected override void OnInitialized()
    {
        if (Parent == null)
            throw new ArgumentNullException(nameof(Parent), "Attribute item must exist within a object view.");

        //Select attribute if it's not static or it's not read.
        if (Attribute != null && (Attribute.Template != null &&
            (Attribute.Template.ExpirationTime == null || Attribute.Template.ExpirationTime.Value.Year != DateTimeOffset.MaxValue.Year) ||
        string.IsNullOrEmpty(Attribute.Value)))
        {
            Parent.ToggleAttribute(Attribute);
        }
        base.OnInitialized();
    }

    /// <summary>
    /// Get attribute value.
    /// </summary>
    /// <param name="attribute">Attribute.</param>
    /// <returns>Value of the attribute.</returns>
    private string? GetAttributeValue(GXAttribute attribute)
    {
        try
        {
            if (GetValue != null)
            {
                string? value = GetValue.Invoke();
                if (attribute.Template?.Scaler is double d1)
                {
                    value = (Convert.ToDouble(attribute.Value) * d1).ToString("0.######");
                }
                return value;
            }
            if (attribute.Template != null)
            {
                DataType dt = (DataType)attribute.Template.UIDataType;
                if (dt == DataType.DateTime)
                {
                    return new GXDateTime(attribute.Value, CultureInfo.InvariantCulture).ToFormatString();
                }
                if (dt == DataType.Date)
                {
                    return new GXDate(attribute.Value, CultureInfo.InvariantCulture).ToFormatString();
                }
                if (dt == DataType.Time)
                {
                    return new GXTime(attribute.Value, CultureInfo.InvariantCulture).ToFormatString();
                }
                if (attribute.Template?.Scaler is double d2)
                {
                    return (Convert.ToDouble(attribute.Value) * d2).ToString("0.######");
                }
            }
            return attribute.Value;
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }

    /// <summary>
    /// Set attribute value.
    /// </summary>
    /// <param name="attribute">Attribute.</param>
    /// <param name="value">The new value of the attribute.</param>
    private void UpdateValue(GXAttribute attribute, object? value)
    {
        try
        {
            if (Index != 0)
            {

            }
            else
            {
                string? tmp;
                if (value is bool b)
                {
                    tmp = b ? "1" : "0";
                }
                else
                {
                    tmp = Convert.ToString(value);
                }
                if (attribute.Template != null)
                {
                    DataType dt = (DataType)attribute.Template.UIDataType;
                    if (dt == DataType.DateTime)
                    {
                        tmp = new GXDateTime(tmp).ToFormatString(CultureInfo.InvariantCulture);
                    }
                    else if (dt == DataType.Date)
                    {
                        tmp = new GXDate(tmp).ToFormatString(CultureInfo.InvariantCulture);
                    }
                    else if (dt == DataType.Time)
                    {
                        tmp = new GXTime(tmp).ToFormatString(CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        if (attribute.Template.Scaler is double s && tmp != null)
                        {
                            tmp = (Convert.ToDouble(tmp) / s).ToString();
                        }
                        //Check that value type is correct.
                        dt = (DataType)attribute.Template.DataType;
                        if (dt != DataType.None)
                        {
                            tmp = Convert.ToString(Convert.ChangeType(tmp, GXDLMSConverter.GetDataType(dt)));
                        }
                    }
                }
                attribute.Value = tmp;
            }
            attribute.Modified = true;
            Updated.InvokeAsync(value);
        }
        catch (Exception ex)
        {
            //TODO: Notify from the error.
            Console.WriteLine(ex.Message);
            throw;
        }
    }

    /// <summary>
    /// Is component disabled.
    /// </summary>
    /// <returns>Trie, if component is disabled.</returns>
    bool IsDisabled()
    {
        return Attribute == null ||
            Attribute.Template == null ||
            (Attribute.Template.AccessLevel & 0x2) == 0;
    }

    bool IsChecked()
    {
        try
        {
            if (Attribute == null)
            {
                return false;
            }
            return Convert.ToBoolean(Attribute.Value);
        }
        catch (Exception)
        {
            return false;
        }
    }
    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    /// <summary>
    /// Value is hidden. Only the title and history are shown.
    /// </summary>
    [Parameter]
    public bool HideValue { get; set; }

    /// <summary>
    /// Target attribute.
    /// </summary>
    [Parameter]
    public GXAttribute? Attribute
    {
        get
        {
            if (Index != 0 && _attribute == null && Attributes != null)
            {
                return GetAttribute(Attributes, Index);
            }
            return _attribute;
        }
        set
        {
            _attribute = value;
        }
    }

    /// <summary>
    /// Get Value.
    /// </summary>
    [Parameter]
    public Func<string?>? GetValue { get; set; }

    public static GXAttribute GetAttribute(List<GXAttribute> attributes, int index)
    {
        foreach (var it in attributes)
        {
            if (it.Template != null && it.Template.Index == index)
            {
                return it;
            }
        }
        throw new ArgumentOutOfRangeException(string.Format("Invalid attribute index {0}", index));
    }

    /// <summary>
    /// Target attributes.
    /// </summary>
    [Parameter]
    public List<GXAttribute>? Attributes { get; set; }


    /// <summary>
    /// Attribute name.
    /// </summary>
    [Parameter]
    public string Name { get; set; } = "";

    /// <summary>
    /// Attribute text.
    /// </summary>
    [Parameter]
    public string Text { get; set; } = "";

    private string InternalText
    {
        get
        {
            return Text;
        }
        set
        {
            Text = value;
            if (Attribute != null)
            {
                Attribute.Modified = true;
            }
            Updated.InvokeAsync(value);
        }
    }

    /// <summary>
    /// Attribute index.
    /// </summary>
    [Parameter]
    public int Index { get; set; }

    [Parameter]
    public EventCallback<object?> Updated { get; set; }

    /// <summary>
    /// Attribute enumerated values.
    /// </summary>
    [Parameter]
    public string[]? Values { get; set; }

}